/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.je.bpm.engine.impl;

import com.je.bpm.engine.ActivitiIllegalArgumentException;
import com.je.bpm.engine.impl.context.Context;
import com.je.bpm.engine.impl.interceptor.CommandContext;
import com.je.bpm.engine.impl.interceptor.CommandExecutor;
import com.je.bpm.engine.repository.Model;
import com.je.bpm.engine.repository.ModelQuery;

import java.util.List;

public class ModelQueryImpl extends AbstractQuery<ModelQuery, Model> implements ModelQuery {

    private static final long serialVersionUID = 1L;
    protected String id;
    protected String category;
    protected String categoryLike;
    protected String categoryNotEquals;
    protected String name;
    protected String nameLike;
    protected String key;
    protected Integer version;
    protected boolean latest;
    protected String deploymentId;
    protected boolean notDeployed;
    protected boolean deployed;
    protected String tenantId;
    protected String tenantIdLike;
    protected boolean withoutTenantId;
    protected String funcCode;
    protected String funcName;
    protected boolean multipleConditionsOrQuery;
    private Integer deployStatus;
    private Integer disabled;

    private static enum ResultType {
        CUSTOMERLIST
    }

    public ModelQueryImpl() {
    }

    public ModelQueryImpl(CommandContext commandContext) {
        super(commandContext);
    }

    public ModelQueryImpl(CommandExecutor commandExecutor) {
        super(commandExecutor);
    }

    @Override
    public ModelQueryImpl modelId(String modelId) {
        this.id = modelId;
        return this;
    }

    @Override
    public ModelQueryImpl modelCategory(String category) {
        if (category == null) {
            throw new ActivitiIllegalArgumentException("category is null");
        }
        this.category = category;
        return this;
    }

    @Override
    public ModelQueryImpl modelCategoryLike(String categoryLike) {
        if (categoryLike == null) {
            throw new ActivitiIllegalArgumentException("categoryLike is null");
        }
        this.categoryLike = categoryLike;
        return this;
    }

    @Override
    public ModelQueryImpl modelCategoryNotEquals(String categoryNotEquals) {
        if (categoryNotEquals == null) {
            throw new ActivitiIllegalArgumentException("categoryNotEquals is null");
        }
        this.categoryNotEquals = categoryNotEquals;
        return this;
    }

    @Override
    public ModelQueryImpl modelName(String name) {
        if (name == null) {
            throw new ActivitiIllegalArgumentException("name is null");
        }
        this.name = name;
        return this;
    }

    @Override
    public ModelQueryImpl modelNameLike(String nameLike) {
        if (nameLike == null) {
            throw new ActivitiIllegalArgumentException("nameLike is null");
        }
        this.nameLike = nameLike;
        return this;
    }

    @Override
    public ModelQuery modelKey(String key) {
        if (key == null) {
            throw new ActivitiIllegalArgumentException("key is null");
        }
        this.key = key;
        return this;
    }

    @Override
    public ModelQueryImpl modelVersion(Integer version) {
        if (version == null) {
            throw new ActivitiIllegalArgumentException("version is null");
        } else if (version <= 0) {
            throw new ActivitiIllegalArgumentException("version must be positive");
        }
        this.version = version;
        return this;
    }

    @Override
    public ModelQuery disabled(Integer disabled) {
        if (disabled == null) {
            throw new ActivitiIllegalArgumentException("name is null");
        }
        this.disabled = disabled;
        return this;
    }

    @Override
    public ModelQuery deployStatus(Integer deployStatus) {
        if (deployStatus == null) {
            throw new ActivitiIllegalArgumentException("name is null");
        }
        this.deployStatus = deployStatus;
        return this;
    }

    @Override
    public ModelQuery modelFuncCode(String funcCode) {
        if (funcCode == null) {
            throw new ActivitiIllegalArgumentException("funcCode is null");
        }
        this.funcCode = funcCode;
        return this;
    }

    @Override
    public ModelQuery modelFuncName(String funcName) {
        if (funcName == null) {
            throw new ActivitiIllegalArgumentException("funcName is null");
        }
        this.funcName = funcName;
        return this;
    }

    @Override
    public ModelQuery latestVersion() {
        this.latest = true;
        return this;
    }

    @Override
    public ModelQuery deploymentId(String deploymentId) {
        if (deploymentId == null) {
            throw new ActivitiIllegalArgumentException("DeploymentId is null");
        }
        this.deploymentId = deploymentId;
        return this;
    }

    @Override
    public ModelQuery notDeployed() {
        if (deployed) {
            throw new ActivitiIllegalArgumentException("Invalid usage: cannot use deployed() and notDeployed() in the same query");
        }
        this.notDeployed = true;
        return this;
    }

    @Override
    public ModelQuery deployed() {
        if (notDeployed) {
            throw new ActivitiIllegalArgumentException("Invalid usage: cannot use deployed() and notDeployed() in the same query");
        }
        this.deployed = true;
        return this;
    }

    @Override
    public ModelQuery modelTenantId(String tenantId) {
        if (tenantId == null) {
            throw new ActivitiIllegalArgumentException("Model tenant id is null");
        }
        this.tenantId = tenantId;
        return this;
    }

    @Override
    public ModelQuery modelTenantIdLike(String tenantIdLike) {
        if (tenantIdLike == null) {
            throw new ActivitiIllegalArgumentException("Model tenant id is null");
        }
        this.tenantIdLike = tenantIdLike;
        return this;
    }

    @Override
    public ModelQuery modelWithoutTenantId() {
        this.withoutTenantId = true;
        return this;
    }

    // sorting ////////////////////////////////////////////
    @Override
    public ModelQuery orderByModelCategory() {
        return orderBy(ModelQueryProperty.MODEL_CATEGORY);
    }

    @Override
    public ModelQuery orderByModelId() {
        return orderBy(ModelQueryProperty.MODEL_ID);
    }

    @Override
    public ModelQuery orderByModelKey() {
        return orderBy(ModelQueryProperty.MODEL_KEY);
    }

    @Override
    public ModelQuery orderByModelVersion() {
        return orderBy(ModelQueryProperty.MODEL_VERSION);
    }

    @Override
    public ModelQuery orderByModelName() {
        return orderBy(ModelQueryProperty.MODEL_NAME);
    }

    @Override
    public ModelQuery orderByCreateTime() {
        return orderBy(ModelQueryProperty.MODEL_CREATE_TIME);
    }

    @Override
    public ModelQuery orderByLastUpdateTime() {
        return orderBy(ModelQueryProperty.MODEL_LAST_UPDATE_TIME);
    }

    @Override
    public ModelQuery orderByTenantId() {
        return orderBy(ModelQueryProperty.MODEL_TENANT_ID);
    }

    @Override
    public ModelQuery multipleConditionsOrQuery() {
        this.setMultipleConditionsOrQuery(true);
        return this;
    }

    // results ////////////////////////////////////////////
    @Override
    public long executeCount(CommandContext commandContext) {
        checkQueryOk();
        return commandContext.getModelEntityManager().findModelCountByQueryCriteria(this);
    }

    @Override
    public List<Model> executeList(CommandContext commandContext, Page page) {
        checkQueryOk();
        if (this.isMultipleConditionsOrQuery()){
            return commandContext.getModelEntityManager().findModelsByMultipleConditionsOrQueryCriteria(this, page);
        }
        return commandContext.getModelEntityManager().findModelsByQueryCriteria(this, page);
    }

    // getters ////////////////////////////////////////////

    public String getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public String getNameLike() {
        return nameLike;
    }

    public Integer getVersion() {
        return version;
    }

    public String getCategory() {
        return category;
    }

    public String getCategoryLike() {
        return categoryLike;
    }

    public String getCategoryNotEquals() {
        return categoryNotEquals;
    }

    public static long getSerialversionuid() {
        return serialVersionUID;
    }

    public String getKey() {
        return key;
    }

    public boolean isLatest() {
        return latest;
    }

    public String getDeploymentId() {
        return deploymentId;
    }

    public boolean isNotDeployed() {
        return notDeployed;
    }

    public boolean isDeployed() {
        return deployed;
    }

    public String getTenantId() {
        return tenantId;
    }

    public String getTenantIdLike() {
        return tenantIdLike;
    }

    public boolean isWithoutTenantId() {
        return withoutTenantId;
    }

    public boolean isMultipleConditionsOrQuery() {
        return multipleConditionsOrQuery;
    }

    public void setMultipleConditionsOrQuery(boolean multipleConditionsOrQuery) {
        this.multipleConditionsOrQuery = multipleConditionsOrQuery;
    }
}
